﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Casters.source.Managers;
using Microsoft.Xna.Framework.Input;

namespace Casters.source.Objects
{
    public class CPlayer : CRenderObject
    {
        public enum Direction { Right = 0, Down, Left, Up, Max };

        // Variables
        public Vector2 m_vPositionOnMap;
        public Vector2 m_vMovePosition;
        public Vector2 m_vMoveDirection;
        public Vector2 m_vCastPosition;
        public Vector2 m_vSightDirection;
        public int[] m_SpellSlots = null;
        public int m_nActiveSpell;
        protected int m_nPlayerNumber;
        protected Vector2 m_vStartingPos;

        // Gameplay stats
        protected int m_nHealth;
        protected int m_nMaxHealth = 100;
        protected int m_nMaxStamina = 8;
        protected int m_nSuperMeter;
        protected int m_nMaxSuperMeter = 10;
        protected int m_nMove = 3;
        protected int m_nTick = 1;

        // Movement variables
        protected List<Direction> m_MoveQueue;
        protected Vector2 m_vMovingPos;
        protected Vector2 m_vDirection;
        protected Vector2 m_vDestination;
        protected float m_fVelocity;
        protected bool m_bIsMoving;


        /// <summary>
        /// Gets a printable string for displaying HP
        /// </summary>
        /// <returns></returns>
        public string GetHealthString()
        {
            return "HP: " + m_nHealth.ToString() + "/" + m_nMaxHealth.ToString();
        }

        /// <summary>
        /// Gets a printable string for displaying Super Meter
        /// </summary>
        /// <returns></returns>
        public string GetSuperMeterString()
        {
            return "Super: " + m_nSuperMeter.ToString() + "/" + m_nMaxSuperMeter.ToString();
        }

        /// <summary>
        /// Takes a value and adds it to Health
        /// 
        /// Caps Health at 0 and MaxHealth
        /// </summary>
        /// <param name="value">Value to Add</param>
        public void ModifyHealth(int value)
        {
            m_nHealth += value;

            if (m_nHealth <= 0)
            {
                m_nHealth = 0;
                CEventSystem.BroadcastEvent(EventID.Player_Dead, m_nPlayerNumber);
            }
            else if (m_nHealth > m_nMaxHealth)
                m_nHealth = m_nMaxHealth;
        }

        /// <summary>
        /// Takes a value and adds it to SuperMetere
        /// 
        /// Caps SuperMeter at 0 and MaxSuperMeter
        /// </summary>
        /// <param name="value"></param>
        public void ModifySuperMeter(int value)
        {
            m_nSuperMeter += value;

            if (m_nSuperMeter < 0)
                m_nSuperMeter = 0;
            else if (m_nSuperMeter > m_nMaxSuperMeter)
                m_nSuperMeter = m_nMaxSuperMeter;
        }

        // Mutators
        public void SetPlayerNumber(int num) { m_nPlayerNumber = num; }
        public bool IncrementTick(int num)
        {
            m_nTick += num;
            if (m_nTick > CCombatManager.GetInstance().GetMaxTicks())
            {
                m_nTick = CCombatManager.GetInstance().GetMaxTicks();
                return false;
            }

            return true;
        }
        public void ResetTick() { m_nTick = 1; }

        // Accessors
        public bool GetIsMoving() { return m_bIsMoving; }
        public int GetTick() { return m_nTick; }
        public bool GetTickMax() { return m_nTick == CCombatManager.GetInstance().GetMaxTicks(); }
        public int GetSpell(int index) { return m_SpellSlots[index]; }

        public CPlayer()
        {
        }

        /// <summary>
        /// Initializes the player
        /// </summary>
        /// <param name="_vPositionOnMap">Tile to be put on</param>
        /// <param name="_vSightDir">Your starting direction</param>
        public void SetupPlayer(Vector2 _vPositionOnMap, Vector2 _vSightDir)
        {
            m_ObjectType = TYPE.Player;

            m_vPositionOnMap = _vPositionOnMap;
            m_vStartingPos = m_vPositionOnMap;
            m_vSightDirection = _vSightDir;

            m_nHealth = m_nMaxHealth;
            m_nSuperMeter = 0;

            // Grabs the selected spells from the spell manager
            if (m_SpellSlots == null)
            {
                m_SpellSlots = new int[6];
                for (int i = 0; i < 6; ++i)
                    m_SpellSlots[i] = CSpellManager.GetInstance().m_SelectedSpells[i];
            }

            m_vDirection = Vector2.Zero;
            m_vMovingPos = Vector2.Zero;
            m_vDestination = Vector2.Zero;
            m_bIsMoving = false;
            m_fVelocity = 250f;

            if(m_MoveQueue == null)
                m_MoveQueue = new List<Direction>();
        }

        /// <summary>
        /// Resets the player back to the starting position
        /// 
        /// Used for showing replays
        /// </summary>
        public void ResetPlayer()
        {
            m_vPositionOnMap = m_vStartingPos;
        }

        /// <summary>
        /// Loads the player and registers for events
        /// </summary>
        public override void LoadContent()
        {
            SetupRenderObject(1, null, Vector2.Zero, Vector2.Zero, Vector2.Zero, "test_player");

            switch (m_nPlayerNumber)
            {
                case 0:
                    SetupPlayer(new Vector2(0, 0), new Vector2(1, 0));
                    break;
                case 1:
                    SetupPlayer(new Vector2(CTileManager.GetInstance().m_vMapSize.X - 1, CTileManager.GetInstance().m_vMapSize.Y - 1), new Vector2(-1, 0));
                    break;
            }
        }

        /// <summary>
        /// Unregister events
        /// </summary>
        public override void UnloadContent()
        {
        }

        /// <summary>
        /// Player Update Function
        /// </summary>
        /// <param name="dt">Delta Time</param>
        public override void Update(float dt)
        {
            if (m_bIsMoving)
            {
                m_vMovingPos += (m_vDirection * m_fVelocity) * dt;

                Vector2 epsilon = new Vector2(7.5f);
                if (m_vMovingPos.X <= m_vDestination.X + epsilon.X && m_vMovingPos.X >= m_vDestination.X - epsilon.X &&
                    m_vMovingPos.Y <= m_vDestination.Y + epsilon.Y && m_vMovingPos.Y >= m_vDestination.Y - epsilon.Y)
                {
                    m_vMovingPos = m_vDestination;
                    m_bIsMoving = false;
                }
            }

            if (m_bIsMoving == false && m_MoveQueue.Count > 0)
            {
                Vector2 dir = Vector2.Zero;
                Vector2 newPos = Vector2.Zero;
                switch (m_MoveQueue[0])
                {
                    case Direction.Right:
                        dir.X = 1f;
                        break;
                    case Direction.Down:
                        dir.Y = 1f;
                        break;
                    case Direction.Left:
                        dir.X = -1f;
                        break;
                    case Direction.Up:
                        dir.Y = -1f;
                        break;
                    default:
                        break;
                }

                newPos = m_vPositionOnMap + dir;
                MovePlayer(newPos);
                m_MoveQueue.RemoveAt(0);
            }

            base.Update(dt);
        }

        /// <summary>
        /// Sets the destination of the player and starts movement
        /// </summary>
        /// <param name="_newPos">New position</param>
        public void MovePlayer(Vector2 _newPos)
        {
            m_vMovePosition = m_vPositionOnMap;
            m_vPositionOnMap = _newPos;
            m_vDestination = CTileManager.GetInstance().GetTileCenterpointPosition(_newPos);
            m_vDirection = m_vDestination - CTileManager.GetInstance().GetTileCenterpointPosition(m_vMovePosition);
            m_vDirection.Normalize();
            m_vMovingPos = CTileManager.GetInstance().GetTileCenterpointPosition(m_vMovePosition);
            m_bIsMoving = true;
        }

        /// <summary>
        /// Adds a single tile movement to the queue
        /// </summary>
        /// <param name="dir">The direction to move</param>
        public void AddToMoveQueue(int dir)
        {
            m_MoveQueue.Add((Direction)dir);
        }

        /// <summary>
        /// Player Render Function
        /// </summary>
        public override void Draw()
        {
            Vector2 RenderPos;

            if (m_bIsMoving)
            {
                m_vPosition = m_vMovingPos;
            }
            else
            {
                // To Render We need to get:
                // Rect Based on bottom center anchor pt
                // Get position of anchor pt from tilemap based on stored position
                // 
                RenderPos = CTileManager.GetInstance().GetTileCenterpointPosition(m_vPositionOnMap);

                m_vPosition = RenderPos;
            }

            SpriteFont font = CGame.GetInstance().Content.Load<SpriteFont>("Fonts/Arial");
            Vector2 camera = CGame.GetInstance().m_Camera.m_vPosition;
            CRenderEngine.DrawString(font, "Player Tick: " + m_nTick.ToString() + "/" + CCombatManager.GetInstance().GetMaxTicks().ToString(), new Vector2(201f, 701f) + camera, Color.Black);
            CRenderEngine.DrawString(font, "Player Tick: " + m_nTick.ToString() + "/" + CCombatManager.GetInstance().GetMaxTicks().ToString(), new Vector2(200f, 700f) + camera, Color.White);
            base.Draw();
        }
    }
}
